package org.arch_learn.servlet_container;

import org.arch_learn.servlet_container.components.Server;
import org.arch_learn.servlet_container.components.Service;
import org.arch_learn.servlet_container.components.container.Context;
import org.arch_learn.servlet_container.components.container.Engine;
import org.arch_learn.servlet_container.components.container.Host;
import org.arch_learn.servlet_container.components.container.Wrapper;

import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.regex.Pattern;

/**
 * 启动主类
 */
public class JerryRat {
    private Server server;

    public Server getServer() {
        return server;
    }

    public JerryRat() {
        this.server = new Server();
    }


    public void run() throws IOException {
        server.getServices().forEach(v -> {
            //多服务循环开启。每一个或者多个服务服务于一个webapp
            v.start();
            System.out.println("==========>>>jerryRat start on port " + v.getPort());
        });
    }

    private void initJerryRatByDefault(Server server) {
        //初始化服务线程池
        ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler abortPolicy = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 50, 100, TimeUnit.SECONDS, blockingQueue, threadFactory, abortPolicy);
        Engine engine = new Engine();
        Context context = new Context(UUID.randomUUID().toString(), "/");
        Host host = new Host("localhost", UUID.randomUUID().toString());
        host.getContexts().put(context.getName(), context);
        engine.addHost(host);
        Service service = new Service(server, UUID.randomUUID().toString(), "8080", engine, threadPoolExecutor);
        server.addService(service);
    }

    public JerryRat addService(Integer port, Integer blockingQueueCapacity, Integer corePoolSize, Integer maximumPoolSize, Integer keepAliveTime) {
        ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(blockingQueueCapacity);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler abortPolicy = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, blockingQueue, threadFactory, abortPolicy);
        Service service = new Service(server, String.valueOf(port), threadPoolExecutor);
        this.server.addService(service);
        return this;
    }

    public JerryRat addEngine() {
        return this;
    }

    public JerryRat addHost(String host) {
        this.getServer().getServices()
                .get(0).getEngine()
                .addHost(new Host(host, null));
        return this;
    }

    public JerryRat addContext(String contextPath) {
        this.getServer().getServices()
                .get(0).getEngine()
                .getHosts().entrySet()
                .stream().findFirst().get()
                .getValue().getContexts()
                .put(contextPath, new Context(UUID.randomUUID().toString(), contextPath));
        return this;
    }

    public void addServlet(String pattern, HttpServlet generalDispatcherServlet) {
        Wrapper wrapper = new Wrapper(UUID.randomUUID().toString(),
                Pattern.compile(pattern),
                generalDispatcherServlet);
        this.getServer()
                .getServices().get(0)
                .getEngine()
                .getHosts().entrySet().stream().findFirst().get().getValue()
                .getContexts().entrySet().stream().findFirst().get().getValue()
                .getWrappers()
                .add(wrapper);
    }

    public void addServlets(Map<String, HttpServlet> servlets) {
        servlets.entrySet()
                .forEach(entry -> addServlet(entry.getKey(), entry.getValue()));
    }
}
